package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.*;
import com.atguigu.exam.mapper.ExamRecordMapper;
import com.atguigu.exam.mapper.PaperMapper;
import com.atguigu.exam.mapper.PaperQuestionMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.PaperQuestionService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.AiPaperVo;
import com.atguigu.exam.vo.PaperVo;
import com.atguigu.exam.vo.RuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 试卷服务实现类
 */
@Slf4j
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {

    @Autowired
    private PaperMapper paperMapper;
    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private QuestionMapper questionMapper;
    @Autowired
    private ExamRecordMapper examRecordMapper;

    /**
     * 获取所有试卷列表（支持模糊搜索和状态筛选）
     *
     * @param name
     * @param status
     * @return
     */
    @Override
    public List<Paper> listPapers(String name, String status) {
        //拼接条件
        LambdaQueryWrapper<Paper> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(!ObjectUtils.isEmpty(name), Paper::getName, name);
        lambdaQueryWrapper.eq(!ObjectUtils.isEmpty(status), Paper::getStatus, status);
        lambdaQueryWrapper.orderByDesc(Paper::getUpdateTime);
        lambdaQueryWrapper.orderByDesc(Paper::getCreateTime);
        //查询
        List<Paper> list = list(lambdaQueryWrapper);
        //返回结果
        return list;
    }

    /**
     * 获取试卷详情（包含题目）
     *
     * @param id
     * @return
     */
    @Override
    public Paper getPaperById(Integer id) {
        //拼接条件
        LambdaQueryWrapper<Paper> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Paper::getId, id);

        //查询试卷基本信息
        Paper paper = getOne(lambdaQueryWrapper);
        if (paper == null) {
            throw new RuntimeException("该试卷不存在");
        }

        //查询题目集合
        List<Question> questionList = paperMapper.selectQuestions(paper.getId());
        log.info("查询所有题目集合为：{}", questionList);
        //判断题目集合是否为空
        if (questionList == null) {
            //设置一个空集合并且返回
            paper.setQuestions(new ArrayList<>());
            return paper;
        }
        //对题目进行排序
        questionList.sort(Comparator.comparing(Question::getType));

        //为题目赋值
        paper.setQuestions(questionList);

        //返回结果
        return paper;
    }

    /**
     * 手动创建试卷
     *
     * @param paperVo
     * @return
     */
    @Transactional
    @Override
    public Paper createPaper(PaperVo paperVo) {
        //创建paper对象
        Paper paper = new Paper();
        //为paper赋值
        BeanUtils.copyProperties(paperVo, paper);
        paper.setStatus("DRAFT");
        if (ObjectUtils.isEmpty(paperVo)) {
            paper.setQuestionCount(0);
            paper.setTotalScore(BigDecimal.ZERO);
            //返回试卷对象
            return paper;
        }
        //题目数量
        paper.setQuestionCount(paperVo.getQuestions().size());
        //计算题目总分数
        BigDecimal totalScore = paperVo.getQuestions().values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        paper.setTotalScore(totalScore);
        //保存paper对象
        save(paper);

        Map<Integer, BigDecimal> questions = paperVo.getQuestions();
        List<PaperQuestion> paperQuestionList = new ArrayList<>();
        Set<Integer> integers = questions.keySet();
        //设置题目分数和题目id
        for (Integer integer : integers) {
            //插入题目
            PaperQuestion paperQuestion = new PaperQuestion();
            //设置试卷id
            paperQuestion.setPaperId(paper.getId());
            //设置题目id
            paperQuestion.setQuestionId(Long.valueOf(integer));
            //设置真实分数
            paperQuestion.setScore(questions.get(integer));
            //添加到试卷题目列表
            paperQuestionList.add(paperQuestion);
        }
        paperQuestionService.saveBatch(paperQuestionList);

        //返回试卷对象
        return paper;
    }


    /**
     * AI智能组卷（新版）
     *
     * @param aiPaperVo
     * @return
     */
    @Override
    public Paper createPaperWithAI(AiPaperVo aiPaperVo) {
        //创建paper对象
        Paper paper = new Paper();
        //为paper赋值
        BeanUtils.copyProperties(aiPaperVo, paper);
        paper.setStatus("DRAFT");

        //校验试卷名称是否存在
        LambdaQueryWrapper<Paper> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Paper::getName, aiPaperVo.getName());
        boolean exists = paperMapper.exists(lambdaQueryWrapper);
        if (exists) {
            throw new RuntimeException("该试卷名称已存在");
        }

        //保存paper对象
        save(paper);
        //获取规则列表
        List<RuleVo> rules = aiPaperVo.getRules();

        List<PaperQuestion> paperQuestionList = new ArrayList<>();
        int questionCount = 0;
        BigDecimal totalScore = BigDecimal.ZERO;
        for (int i = 0; i < rules.size(); i++) {
            RuleVo ruleVo = rules.get(i);

            if (ruleVo.getCount() == 0) {
                log.warn("在：{}类型下，不需要出题！", ruleVo.getType().name());
                continue;
            }
            //拼接条件,查询符合要求的题目
            LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            questionLambdaQueryWrapper.eq(Question::getType, ruleVo.getType());
            questionLambdaQueryWrapper.in(!ObjectUtils.isEmpty(ruleVo.getCategoryIds()),
                    Question::getCategoryId, ruleVo.getCategoryIds());
            List<Question> questionList = questionMapper.selectList(questionLambdaQueryWrapper);

            //如果查询到的题目为空则跳过下列操作
            if (ObjectUtils.isEmpty(questionList)) {
                log.warn("在：{}类型下，我们指定的分类：{},没有查询到题目信息！", ruleVo.getType().name(), ruleVo.getCategoryIds());
                continue;
            }

            //打乱集合
            Collections.shuffle(questionList);

            int min = Math.min(questionList.size(), ruleVo.getCount());
            //本次规则下添加的数量和分数累加
            questionCount += min;
            totalScore = totalScore.add(BigDecimal.valueOf(min * ruleVo.getScore()));
            //获取的所有题目
            List<Question> questionList1 = questionList.subList(0, min);
            //截取题目列表
            for (Question question : questionList1) {
                PaperQuestion paperQuestion = new PaperQuestion();
                paperQuestion.setScore(BigDecimal.valueOf(ruleVo.getScore()));
                paperQuestion.setPaperId(paper.getId());
                paperQuestion.setQuestionId(question.getId());
                paperQuestionList.add(paperQuestion);
            }
        }
        //保存中间表
        paperQuestionService.saveBatch(paperQuestionList);

        //设置试卷的总分和总题数
        paper.setQuestionCount(questionCount);
        paper.setTotalScore(totalScore);
        updateById(paper);
        //返回结果
        return paper;
    }

    /**
     * 更新试卷
     *
     * @param paperVo
     * @return
     */
    @Override
    public Paper updatePaper(Integer id, PaperVo paperVo) {
        //1.首先判断试卷的发布状态
        Paper paper = getById(id);
        //进行判断
        if ("PUBLISHED".equals(paper.getStatus())) {
            throw new RuntimeException("发布状态下的试卷不能进行修改");
        }
        //判断试卷是否重名
        LambdaQueryWrapper<Paper> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Paper::getName, paper.getName());
        lambdaQueryWrapper.ne(Paper::getId, paper.getId());
        long count = count(lambdaQueryWrapper);
        if (count > 0) {
            throw new RuntimeException("%s 试卷名字已经存在，请重新修改！".formatted(paperVo.getName()));
        }

        ////2.为paper修改值
        BeanUtils.copyProperties(paperVo, paper);
        //设置总分数
        paper.setTotalScore(paperVo.getQuestions().values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
        //设置题目数
        paper.setQuestionCount(paperVo.getQuestions().size());

        //3.先删除后增加试卷题目中间表
        LambdaQueryWrapper<PaperQuestion> paperQuestionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        paperQuestionLambdaQueryWrapper.eq(PaperQuestion::getPaperId, paper.getId());
        remove(lambdaQueryWrapper);


        //4.试卷题目中间表批量增加数据
        List<PaperQuestion> paperQuestionList = paperVo.getQuestions().entrySet().stream().map(entry ->
                new PaperQuestion(paper.getId(), Long.valueOf(entry.getKey()), entry.getValue())).collect(Collectors.toList());
        paperQuestionService.saveBatch(paperQuestionList);
        //5.更新paper
        updateById(paper);


        return paper;
    }

    /**
     * 更新试卷状态（发布/停止）
     *
     * @param id
     * @param status
     */

    @Override
    public void updatePaperStatus(Integer id, String status) {
        //1.判断试卷要修改的状态是否为发布
        if ("PUBLISHED".equals(status)) {
            //判断题目数量是否不为0
            long count = paperQuestionService.count(
                    new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
            if (count == 0) {
                throw new RuntimeException("试卷中无题目,无法进行发布");
            }
        }

        //更新试卷
        LambdaUpdateWrapper<Paper> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Paper::getId, id);
        lambdaUpdateWrapper.set(Paper::getStatus, status);
        update(lambdaUpdateWrapper);
    }

    /**
     * 删除试卷
     *
     * @param id
     */
    @Transactional
    @Override
    public void deletePaper(Integer id) {
        Paper paper = getById(id);
        //判断试卷是否存在
        if (paper == null || "PUBLISHED".equals(paper.getStatus())) {
            throw new RuntimeException("发布状态的试卷无法删除");
        }
        //判断是否有考试记录
        LambdaQueryWrapper<ExamRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ExamRecord::getExamId, id);
        Long count = examRecordMapper.selectCount(lambdaQueryWrapper);
        if (count > 0) {
            throw new RuntimeException("该试卷下关联了: %s 条记录,无法被删除".formatted(count));
        }
        //删除试卷表中数据
        removeById(Long.valueOf(id));
        //删除试卷题目表数据
        paperQuestionService.remove(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, paper.getId()));
    }
}